﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Battleship
{
    public class ContainerManager
    {
        public int depth;
        public int width;
        public int height;

        private List<ContainerModel> containers = new List<ContainerModel>();
        public int[][,] positions;

        public ContainerManager(int width, int height, int depth)
        {
            this.width = width;
            this.height = height;
            this.depth = depth;

            positions = new int[depth][,];
            for (int i = 0; i < depth; i++)
            {
                positions[i] = new int[width, height];
                for (int j = 0; j < width; j++)
                {
                    for (int k = 0; k < height; k++)
                    {
                        positions[i][j, k] = -1;
                    }
                }
            }
        }

        public bool inRange(int value, int max, int min = 0)
        {
            return value >= min && value < max;
        }

        private bool checkPosition(Position position, int size = 1)
        {
            return inRange(position.x, width) && inRange(position.y, height) && inRange(position.z, depth - size + 1);
        }

        public bool checkPosition(ContainerModel container)
        {
            Position position = container.position;
            int size = container.size;

            return checkPosition(position, size);
        }

        private void setPosition(Position pos, int size, int value)
        {
            for (int i = pos.z; i < pos.z + size; i++)
            {
                positions[i][pos.x, pos.y] = value;
            }
        }

        private int getIndex(ContainerModel container)
        {
            if (container == null)
            {
                return -1;
            }

            return containers.IndexOf(container);
        }

        public bool put(ContainerModel container)
        {
            if (!checkPosition(container))
            {
                return false;
            }

            int size = container.size;
            for (int i = 0; i < size; i++)
            {
                if (!checkPosition(container.position))
                {
                    return false;
                }
            }

            int index = containers.Count;
            containers.Add(container);
            setPosition(container.position, size, index);

            return true;
        }

        public ContainerModel get(Position pos)
        {
            int index = positions[pos.z][pos.x, pos.y];
            if (index != -1)
            {
                return containers[index];
            }

            return null;
        }

        public bool swap(Position clickPointA, Position clickPointB)
        {
            ContainerModel containerA = get(clickPointA);
            ContainerModel containerB = get(clickPointB);

            if (containerA != null && containerB != null)
            {
                Position posA = containerA.position;
                Position posB = containerB.position;

                int indexA = getIndex(containerA);
                int indexB = getIndex(containerB);

                if (containerA.size == containerB.size)
                {
                    setPosition(posA, containerA.size, indexB);
                    containerA.position = posB;

                    setPosition(posB, containerA.size, indexA);
                    containerB.position = posA;

                }
                else
                {
                    ContainerModel containerSize1 = null;
                    ContainerModel containerSize2 = null;

                    if (containerA.size == 1)
                    {
                        containerSize1 = containerA;
                        containerSize2 = containerB;
                    }
                    else
                    {
                        containerSize1 = containerB;
                        containerSize2 = containerA;
                    }

                    posA = containerSize1.position;
                    posB = containerSize2.position;

                    indexA = getIndex(containerSize1);
                    indexB = getIndex(containerSize2);

                    Position posC = posA.clone();
                    posC.z = posC.z + (posC.z % 2 == 0 ? 1 : -1);

                    Position posD = posB.clone();
                    posD.z = posD.z + 1;

                    ContainerModel containerC = get(posC);
                    int indexC = getIndex(containerC);

                    if (posA.z % 2 == 0)
                    {
                        setPosition(posA, containerSize2.size, indexB);
                        containerSize2.position = posA;

                        setPosition(posB, 1, indexA);
                        containerSize1.position = posB;

                        setPosition(posD, 1, indexC);
                        if (containerC != null)
                        {
                            containerC.position = posD;
                        }
                    }
                    else
                    {
                        setPosition(posC, containerSize2.size, indexB);
                        containerSize2.position = posC;

                        setPosition(posB, 1, indexC);
                        if (containerC != null)
                        {
                            containerC.position = posB;
                        }

                        setPosition(posD, 1, indexA);
                        containerSize1.position = posD;
                    }
                }

                return true;
            }
            else if (containerA != null || containerB != null)
            {
                ContainerModel container = null;
                Position clickPoint = null;

                if (containerA != null)
                {
                    container = containerA;
                    clickPoint = clickPointB;
                }
                else
                {
                    container = containerB;
                    clickPoint = clickPointA;
                }

                int index = getIndex(container);

                if (container.size == 1)
                {
                    setPosition(clickPoint, 1, index);
                    setPosition(container.position, container.size, -1);
                    container.position = clickPoint;
                }
                else
                {
                    Position posC = clickPoint.clone();
                    posC.z = posC.z + (posC.z % 2 == 0 ? 0 : -1);

                    setPosition(posC, 2, index);
                    setPosition(container.position, container.size, -1);
                    container.position = posC;
                }

                return true;
            }

            return false;
        }
    }
}
